package io.xxx.xbutler.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.xxx.xbutler.common.ApplicationException;
import io.xxx.xbutler.data.TaskTemplateItemMapper;
import io.xxx.xbutler.data.TaskTemplateMapper;
import io.xxx.xbutler.data.TaskTemplatePeriodMapper;
import io.xxx.xbutler.domain.task.TaskTemplate;
import io.xxx.xbutler.domain.task.TaskTemplateItem;
import io.xxx.xbutler.domain.task.TaskTemplatePeriod;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class TaskTemplateService {

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private TransactionTemplate transactionTemplate;

    @Resource
    private TaskTemplateMapper templateMapper;

    @Resource
    private TaskTemplatePeriodMapper templatePeriodMapper;

    @Resource
    private TaskTemplateItemMapper templateItemMapper;

    public Page<TaskTemplate> list(TaskTemplate template, Page<TaskTemplate> page) {
        LambdaQueryWrapper<TaskTemplate> wrapper = new LambdaQueryWrapper<TaskTemplate>();
        if (template.getId() != null) {
            wrapper.eq(TaskTemplate::getId, template.getId());
        }
        if (StringUtils.hasText(template.getName())) {
            wrapper.like(TaskTemplate::getName, template.getName());
        }
        if (template.getAreaId() != null) {
            wrapper.eq(TaskTemplate::getAreaId, template.getAreaId());
        }
        if (template.getOperateAreaId() != null) {
            wrapper.eq(TaskTemplate::getOperateAreaId, template.getOperateAreaId());
        }
        if (StringUtils.hasText(template.getCreatedName())) {
            wrapper.like(TaskTemplate::getCreatedName, template.getCreatedName());
        }

        return templateMapper.selectPage(page, wrapper);
    }

    public TaskTemplate get(Long id) {
        TaskTemplate template = templateMapper.selectById(id);
        if (template != null) {
            LambdaQueryWrapper<TaskTemplatePeriod> periodWrapper = new LambdaQueryWrapper<TaskTemplatePeriod>()
                    .eq(TaskTemplatePeriod::getTemplateId, id);
            List<TaskTemplatePeriod> templatePeriods = templatePeriodMapper.selectList(periodWrapper);
            template.setPeriods(templatePeriods);

            LambdaQueryWrapper<TaskTemplateItem> itemWrapper = new LambdaQueryWrapper<TaskTemplateItem>()
                    .eq(TaskTemplateItem::getTemplateId, id);
            List<TaskTemplateItem> templateItems = templateItemMapper.selectList(itemWrapper);
            Map<Integer, List<TaskTemplateItem>> items = templateItems.stream()
                    .collect(Collectors.groupingBy(TaskTemplateItem::getPsn));
            template.setItems(new ArrayList<>(items.values()));
        }
        return template;
    }

    public void create(TaskTemplate template, List<TaskTemplatePeriod> periods, List<TaskTemplateItem> items) {
        transactionTemplate.executeWithoutResult(_ -> {
            templateMapper.insert(template);
            templatePeriodMapper.insert(periods);
            templateItemMapper.insert(items);
        });
    }

    public void update(TaskTemplate template, List<TaskTemplatePeriod> periods, List<TaskTemplateItem> items) {
        Long templateId = template.getId();
        RLock lock = redissonClient.getLock("lock:task_template:update:" + templateId);
        try {
            if (!lock.tryLock()) {
                log.info("任务模板正在被其他人修改[taskId:{}]", templateId);
                throw new ApplicationException(100_002, "任务模板正在被其他人修改");
            }
            LambdaQueryWrapper<TaskTemplatePeriod> periodWrapper = new LambdaQueryWrapper<TaskTemplatePeriod>()
                    .eq(TaskTemplatePeriod::getTemplateId, templateId);
            LambdaQueryWrapper<TaskTemplateItem> itemWrapper = new LambdaQueryWrapper<TaskTemplateItem>()
                    .eq(TaskTemplateItem::getTemplateId, templateId);
            transactionTemplate.executeWithoutResult(_ -> {
                int count = templateMapper.updateById(template);
                if (count > 0) {
                    templatePeriodMapper.delete(periodWrapper);
                    templatePeriodMapper.insert(periods);

                    templateItemMapper.delete(itemWrapper);
                    templateItemMapper.insert(items);
                }
            });
        } finally {
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    public void delete(Long templateId) {
        LambdaQueryWrapper<TaskTemplatePeriod> periodWrapper = new LambdaQueryWrapper<TaskTemplatePeriod>()
                .eq(TaskTemplatePeriod::getTemplateId, templateId);
        LambdaQueryWrapper<TaskTemplateItem> itemWrapper = new LambdaQueryWrapper<TaskTemplateItem>()
                .eq(TaskTemplateItem::getTemplateId, templateId);
        transactionTemplate.executeWithoutResult(_ -> {
            templateMapper.deleteById(templateId);
            templatePeriodMapper.delete(periodWrapper);
            templateItemMapper.delete(itemWrapper);
        });
    }
}
